home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1989 …il & Dave's Excellent CD / Excellent CD HFS.raw / Moof / Goodies / MPW Goodies / Interfaces / AStructMacs / ProgStrucMacs.a < prev    next >
Encoding:
Text File  |  1988-11-30  |  51.1 KB  |  1,100 lines  |  [TEXT/MPS ]

  1.         PRINT    Push,NoObj
  2.         TITLE    'ProgStrucMacs - Program Structure Macro Statements'
  3.         
  4. *******************************************************************************
  5. *                                                                             *
  6. *                                ProgStrucMacs                                *
  7. *                                                                             *
  8. *                        Program Structure Statements                         *
  9. *                                                                             *
  10. *                                Ira L. Ruben                                 *
  11. *                                  09/15/86                                   *
  12. *                                                                             *
  13. *                  Copyright Apple Computer, Inc. 1986-1988                   *
  14. *                             All rights reserved.                            *
  15. *                                                                             *
  16. *       ---------------------------------------------------------------       *
  17. *                                                                             *
  18. * External macros in this set are:                                            *
  19. *                                                                             *
  20. *   • Procedure - Parse a procedure declaration                               *
  21. *   • Function  - Parse a function declaration                                *
  22. *   • Var       - Declare local variables on the stack                        *
  23. *   • Begin     - Procedure primary entry point                               *
  24. *   • Enter     - Procedure secondary entry point                             *
  25. *   • Return    - Procedure and function exit                                 *
  26. *   • Call      - procedure, function, or trap call                           *
  27. *                                                                             *
  28. * Internal macros in this set are:                                            *
  29. *                                                                             *
  30. *   • ScanArgs# - Parse a proc name and its argument list                     *
  31. *   • Dcl1Var#  - Process local variable declaration or formal param          *
  32. *                                                                             *
  33. * Thanks to Steve Brecher of Software Supply whose original set of macros     *
  34. * provided many ideas and syntax used here.                                   *
  35. *                                                                             *
  36. *******************************************************************************
  37.  
  38.  
  39.         TITLE    'ScanArgs# - Parse a proc name and its argument list'
  40.         
  41.         MACRO
  42.         ScanArgs#    &ArgList
  43. .*
  44. .******************************************************************************
  45. .* ScanArgs# - Parse a proc name and its argument list       (internal macro) *
  46. .*                                                                            *
  47. .* Input:  &ArgList = <modname> ['('arg1,...argN')'] [':'<result>]            *
  48. .*                                                                            *
  49. .* Output: &ModName#   = <modname>                                     (SETC) *
  50. .*         &NbrOfArgs# = number of arguments                           (SETA) *
  51. .*         &Args#      = array of arguments; &Args#[i] = i'th arg      (SETC) *
  52. .*         &FInfo#     = <result>                                      (SETC) *
  53. .******************************************************************************
  54. .*
  55.         GBLC        &ModName#            ; <modname>
  56.         GBLC        &FInfo#            ; <result>
  57.         GBLC        &Args#[50]        ; argument list
  58.         GBLA        &NbrOfArgs#        ; number of args in argument list
  59. .*
  60.         LCLC        &S,&F[2]
  61.         LCLA        &i
  62. .*
  63.     &S: SETC &Trim(&ArgList)            ; Ignore leading/trailing blanks
  64.     &i: SETA &Pos('(', &S)            ; Find left-most "(", if any
  65.     IF &i = 0 THEN                    ; If no args...
  66.       &NbrOfArgs#: SETA 0            ; ...say so!
  67.       &i:          SETA &List(&S, '&F', ':')
  68.       &ModName#:   SETC &Trim(&F[1])    ; Set &ModName# to stuff before any ":"
  69.       &FInfo#:     SETC    &Trim(&F[2])    ; &FInfo# is everything to right of ":"
  70.     ELSE                            ; If there are args, set up globals
  71.       &ModName#:   SETC &Trim(&ArgList[1:&i-1])
  72.       &NbrOfArgs#: SETA &List(&ArgList[&i+1:255], '&Args#')
  73.       &i:          SETA &List(&Args#[&NbrOfArgs#], '&F', ')')
  74.       &Args#[&NbrOfArgs#]: SETC &Trim(&F[1])
  75.       &FInfo#:      SETC &SubStr(&Trim(&F[2]), 2, 255)
  76.     ENDIF
  77. .*
  78. .*&i    seta    0
  79. .*    writeln
  80. .*    writeln    &ModName#
  81. .*    while &i < &NbrOfArgs# do
  82. .*      &i: seta &i+1
  83. .*      writeln &i, ': "', &Args#[&i], '"'
  84. .*    endw
  85. .*    writeln    '"', &FInfo#, '"'
  86. .*    print    pop
  87.         ENDM
  88.  
  89.  
  90.         TITLE    'Dcl1Var# - Process local variable decl. or formal param'
  91.         
  92.         MACRO
  93.         Dcl1Var#    &Opnd,&Align:A=0
  94. .*
  95. .******************************************************************************
  96. .* Dcl1Var# - Process local variable decl. or formal param   (internal macro) *
  97. .*                                                                            *
  98. .* Input:  &Opnd  = <id>[':' <size>] [ '[' <dim> ']']                         *
  99. .*         &Align = 1 ==> Align to word boundary and round size up to even    *
  100. .*                  0 ==> no alignment and no rounding                        *
  101. .*                                                                            *
  102. .* Output: None.                                                              *
  103. .*                                                                            *
  104. .* Code:   If <size> is a template name:      DS.W      <size>                *
  105. .*         If <size> is B, W, L, S, D, X, P:  DS.<size> <dim>         Note 1  *
  106. .*         If <size> anything else:           DS.B      <dim>*<size>  Note 2  *
  107. .*                                                                            *
  108. .*         Note 1: If <size>=B and &Align=1, then <size> forced to W          *
  109. .*         Note 2: If &Align=1, then <size> rounded to next word if odd       *
  110. .******************************************************************************
  111. .*
  112.         LCLC        &Var,&Size,&UCSize,&A[2]
  113.         LCLA        &VarLen,&i,&j,&Dim
  114. .*
  115.     &Var:    SETC &Trim(&Opnd)        ; Assume there is anly an <id> 
  116.     &VarLen: SETA &Len(&Opnd)        ; To be sure we look at last char
  117. .*
  118. .* Process '[' <dim> ']'
  119. .*
  120.     IF &Var[&VarLen] ≠ ']' THEN        ; Have "]" indicating we have <dim> ?
  121.       &Dim: SETA 1                    ; No, the <dim> defaults to 1
  122.     ELSE                            ; If we have a <dim>...
  123.       &i: SETA -&ScanEQ('[', &Var, -&VarLen) ; Find "[" preceding the <dim>
  124.       IF &i = &VarLen THEN            ; Did we find it ? (we better!)
  125.         AERROR '"[" missing.'        
  126.         &Dim: SETA 1                ; No, default to 1
  127.         &Var: SETA &Var[1:&VarLen-1]    ; Remove the invalid <dim> from the <id>
  128.       ELSE
  129.         &j:   SETA &VarLen-&i        ; If we have a valid <dim>
  130.         &Dim: SETA &Eval(&Var[&j+1:&i]); Extract it
  131.         &Var: SETC &Trim(&Var[1:&j-1]) ; Remove it from the <id>
  132.       ENDIF
  133.     ENDIF
  134. .*
  135. .* Process ':' <size>
  136. .*
  137.     &i:      SETA &List(&Var, '&A', ':')        ; Split <size> off the <id>
  138.     &Var:    SETC &Trim(&A[1])                ; Put <id> in &Var
  139.     &Size:   SETC &Default(&Trim(&A[2]), 'W')    ; Put <size> in &Size
  140.     &UCSize: SETC &UC(&Size)                    ; Need upper case copy to test
  141. .*
  142. .* Put it all together -- generate appropriate DC statement
  143. .*
  144.     IF &Type(&Size) = 'TEMPLATE' THEN
  145.       IF &Dim ≠ 1 THEN
  146.         AERROR 'Dimension must be 1 for template types'
  147.       ENDIF
  148. &Var      DS.W      &Size
  149.     ELSEIF (&UCSize = 'W') OR (&Align AND (&UCSize = 'B')) THEN
  150. &Var      DS.W      &Dim
  151.     ELSEIF (&Len(&UCSize) = 1) AND (&Pos(&UCSize, 'BLSDXP') > 0) THEN
  152. &Var      DS.&Size  &Dim
  153.     ELSE
  154.       &i: SETA &Ord(&Eval(&Size))
  155.       IF &Align THEN
  156. &Var      DS.B      &Dim*(&i+(&i**1))
  157.       ELSE
  158. &Var      DS.B      &Dim*&i
  159.       ENDIF
  160.     ENDIF
  161. .*
  162.         ENDM
  163.  
  164.  
  165.         TITLE    'Procedure - Parse a procedure declaration'
  166.         
  167.         MACRO
  168. &Scope    Procedure    &ArgList,&C,&Link==,&Main==N
  169. .*
  170. .******************************************************************************
  171. .* Procedure - Parse a procedure declaration                                  *
  172. .*                                                                            *
  173. .* Input:  &ArgList = <modname> ['('formal1,...formalN')'] [':'<result>]      *
  174. .*         <result> = B | W | L | S | D | X | P | <id>                        *
  175. .*         &Scope   = 'ENTRY'  ==> procedure local to file                    *
  176. .*                    'EXPORT' ==> procedure global to file                   *
  177. .*                    'LOCAL'  ==> procedure local to current procedure       *
  178. .*                    <null>   ==> same as ENTRY                              *
  179. .*         &C       = 'C' ==> a C routine, reverse args on the stack          *
  180. .*         &Link    = 'Y'     ==> generate LINK A6                            *
  181. .*                    'DEBUG' ==> generate LINK A6 and MacsBug symbol         *
  182. .*                    <null>  ==> generate LINK A6 if LinkAll or Debug is 1   *
  183. .*         &Main    = 'Y'     ==> main program                                *
  184. .*                    not 'Y' ==> not main program                            *
  185. .*                                                                            *
  186. .*         Globals: LinkAll ≠ 0 ==> always generate LINKs                     *
  187. .*                          = 0 ==> LINK's subject to &Link param             *
  188. .*                  Debug   ≠ 0 ==> always generate LINKs and MacsBug symbol  *
  189. .*                          = 0 ==> LINKs/MacsBug symbol subject to &Link     *
  190. .*                                                                            *
  191. .* Output: &StFrame#  = name of current stack frame (SF#xxxx)          (SETC) *
  192. .*         &DbgName#  = name to generate for MacsBug or <null>         (SETC) *
  193. .*         &FSz#      = function result size or <null>                 (SETC) *
  194. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  195. .*         &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  196. .*         &C#        = 1 ==> C function; 0 ==> Pascal routine         (SETA) *
  197. .*                                                                            *
  198. .* Code: * The following is generated by Procedure (HERE IN THIS MACRO)       *
  199. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  200. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  201. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  202. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  203. .*                  - - -                                                     *
  204. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  205. .*       RetAddr    DS.L        1                ; Return address             *
  206. .*       -------------------------------------------------------------------- *
  207. .*       * The following is generated by Var                                  *
  208. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  209. .*       FramePtr   EQU         *                ; A6 will point here         *
  210. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  211. .*                  - - -                                                     *
  212. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  213. .*       -------------------------------------------------------------------- *
  214. .*       * The following is generated by Begin                                *
  215. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  216. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  217. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  218. .*                  ENDR                         ; End of local stack frame   *
  219. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  220. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  221. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  222. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  223. .*       -------------------------------------------------------------------- *
  224. .*       * The following is generated by Enter                                *
  225. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  226. .*       Lbl                                     ; 2ndary entry point label   *
  227. .*                 [WITH        <with>]          ; Cover additional templates *
  228. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  229. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  230. .*       %L%xxxx                                 ; The branch-around label    *
  231. .*       -------------------------------------------------------------------- *
  232. .*       * Body of procedure goes here                                        *
  233. .*       -------------------------------------------------------------------- *
  234. .*       * The following is generated by Return                               *
  235. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  236. .*                 [UNLK        A6]              ; Only if LINK was done      *
  237. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  238. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  239. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  240. .*                 [JMP         (A0)]            ; If not C and have args     *
  241. .*                 [RTS             ]            ; If C or no args            *
  242. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  243. .******************************************************************************
  244. .*
  245.         PRINT    Push,NoMDir,NoMCall
  246. .*
  247.         GBLC        &ModName#            ; <modname>
  248.         GBLC        &FInfo#            ; function <result>
  249.         GBLC        &Args#[50]        ; argument list
  250.         GBLA        &NbrOfArgs#        ; number of args in argument list
  251.         GBLC        &StFrame#            ; name of current stack frame
  252.         GBLC        &DbgName#            ; name to generate for MacsBug
  253.         GBLC        &FSz#            ; function result size
  254.         GBLA        &Link#            ; 1 ==> generate LINK
  255.         GBLA        &HaveDcls#        ; 1 ==> have local variables
  256.         GBLA        &C#                ; 1 ==> C function
  257. .*
  258.         LCLA        &Func,&Arg
  259.         LCLC        &LinkOpt
  260.         LCLC        &DbgTemp
  261. .*
  262. .* LinkAll is a user setable global controlling LINK generation
  263. .*
  264.     IF &Type('LinkAll') = 'UNDEFINED' THEN ; Initialize LinkAll if required
  265.       PRINT Push,Off
  266.       LinkAll: SET 0
  267.       PRINT Pop
  268.     ENDIF
  269. .*
  270. .* Debug is a user setable global controlling MacsBug symbol generation
  271. .*
  272.     IF &Type('Debug') = 'UNDEFINED' THEN ; Initialize Debug if required
  273.       PRINT Push,Off
  274.       Debug: SET 0
  275.       PRINT Pop
  276.     ENDIF
  277. .*
  278. .* Break up &ArgList into its components
  279. .*
  280.     ScanArgs#    &ArgList                ; Set &ModName#, &Args#, &FInfo#
  281.     &Func: SETA &Len(&FInfo#)        ; &Func ≠ 0 if function
  282.     &C#:   SETA &UC(&C)='C'            ; Remember if we have a C function
  283. .*
  284.       IF &NbrOfArgs# = 1 THEN            ; Correct for the case F()
  285.           IF &Args#[1] = '' THEN            ; One arg but it's null...
  286.         &NbrOfArgs#: SETA 0            ; ...treat as if there are no arguments
  287.           ENDIF
  288.       ENDIF
  289. .*
  290. .* Generate module header and its corresponding scope
  291. .*
  292.     IF &UC(&Scope) = 'LOCAL' THEN
  293.           ALIGN
  294.       IF &ModName# ≠ '' THEN
  295. &ModName#:
  296.       ENDIF
  297.     ELSEIF &UC(&Main[1:1]) = 'Y' THEN
  298. &ModName# MAIN      &Scope
  299.     ELSEIF &Func THEN
  300. &ModName# FUNC      &Scope
  301.     ELSE
  302. &ModName# PROC      &Scope
  303.     ENDIF
  304. .*
  305. .* Start the proc's local stack frame
  306. .*
  307.     &StFrame#: SETC &Concat('SF#', &SysNdx)
  308. .*
  309. &StFrame# RECORD    {FramePtr},Decr
  310. .*
  311. .* If function, then generate stack fram label for function result. The label is
  312. .* the module name if function result is one of the standard sizes.  If it is not
  313. .* a standard size, it is assumed to be an <id> and that <id> is used as the
  314. .* function result label.
  315. .*
  316.     IF &Func THEN
  317.       IF (&Func = 1) AND (&Pos(&UC(&FInfo#), 'BWLSDXP') > 0) THEN
  318.         &FSz#: SETC &UC(&FInfo#)
  319. &ModName# DS.&FSz#  0
  320.       ELSE
  321.         &FSz#: SETC 'W'
  322. &FInfo#   DS.W        0
  323.       ENDIF
  324.     ELSE
  325.       &FSz#: SETC ''
  326.     ENDIF
  327. .*
  328. .* Declare all the formals in the local stack frame.  The formals are declared
  329. .* in the reverse order if we have a C function.
  330. .*
  331.     IF &C# THEN                    ; C ?
  332.       &Arg: SETA &NbrOfArgs#            ; Yes
  333.       WHILE &Arg > 0 DO                ; Declare formals in reverse order
  334.         Dcl1Var# &Args#[&Arg],1
  335.         &Arg: SETA &Arg-1
  336.       ENDW
  337.     ELSE                            ; Pascal
  338.       WHILE &Arg < &NbrOfArgs# DO        ; Declare formals in the "normal" way
  339.         &Arg: SETA &Arg+1
  340.         Dcl1Var# &Args#[&Arg],1      
  341.       ENDW
  342.     ENDIF
  343. .*
  344. .* The return address always follows the formal list
  345. .*
  346. RetAddr   DS.L      1
  347. .*
  348. .* Process the &Link parameter: indicates if LINK must be generated and whether
  349. .* MacsBug symbol will be generated.
  350. .*
  351.     &Link#:   SETA 0                ; Assume LINK will not be needed
  352.     &LinkOpt: SETC &UC(&Link)
  353.     IF Debug THEN                    ; If Debug ≠ 0 then...
  354.       &LinkOpt: SETC 'DEBUG'            ; ...we will gen LINK and MacsBug symbol
  355.     ELSEIF LinkAll THEN                ; If LinkAll ≠ 0 then...
  356.       IF &LinkOpt ≠ 'DEBUG' THEN        ; ...if user didn't specify DEBUG for &Link
  357.         &LinkOpt: SETC 'Y'            ; indicate we need the LINK
  358.       ENDIF
  359.     ENDIF
  360.     IF &LinkOpt ≠ '' THEN            ; Any &Link or global control setting ?
  361.       &Link#: SETA 1                ; Yes, set switch to gen LINK later
  362.       IF (&LinkOpt ≠ 'DEBUG') OR (&ModName# = '') THEN
  363.         &DbgName#: SETC ''            ; If no MacsBug symbol, set global <null>
  364.       ELSE                        ; If MacsBug symbol, set it to gen later
  365.         &DbgTemp: SETC    &ModName#        ; Generate new type symbols
  366.         IF &Len(&ModName#) < 32 THEN    ; If module name < 32 chars
  367.          IF &Len(&ModName#) // 2 = 0 THEN ; Add space if even so that...
  368.            &DbgTemp: SETC &Concat(&ModName#,' ') ; string length plus length byte...
  369.           ENDIF                    ; will align to word boundary
  370.           &DbgName#: SETC &Concat(&Chr($80 + &Len(&ModName#)), &DbgTemp)
  371.         ELSE                        ; Length is greater than 32 characters
  372.          IF &Len(&ModName#) // 2 = 1 THEN ; Add space if length is odd
  373.            &DbgTemp: SETC &Concat(&ModName#,' ')
  374.          ENDIF
  375.          &DbgName#: SETC &Concat(&Chr($80), &Chr(&Len(&ModName#)), &DbgTemp)
  376.         ENDIF
  377.       ENDIF
  378.     ENDIF
  379. .*
  380. .* That's all for now -- we have no local declarations at this point...yet!
  381. .*
  382.     &HaveDcls#: SETA 0
  383. .*
  384.         PRINT    Pop
  385.         ENDM
  386.  
  387.  
  388.         TITLE    'Function - Parse a function declaration'
  389.         
  390.         MACRO
  391. &Scope    Function    &ArgList,&C,&Link==,&Main==N
  392. .*
  393. .******************************************************************************
  394. .* Function - Parse a function declaration (see Procedure for details)        *
  395. .******************************************************************************
  396. .*                                                                            *
  397.         PRINT    Push,NoMDir,NoMCall
  398. .*
  399. &Scope    Procedure    &ArgList,&C,Link=&Link,Main=&Main
  400. .*
  401.         PRINT    Pop
  402.         ENDM
  403.  
  404.  
  405.         TITLE    'Var - Declare local variables on the stack'
  406.         
  407.         MACRO
  408.         Var
  409. .*
  410. .******************************************************************************
  411. .* Var - Declare local variables on the stack                                 *
  412. .*                                                                            *
  413. .* Call:   <var-id>  Var   <id>[':' <size>] [ '[' <dim> ']']   (See Dcl1Var#) *
  414. .*                                                                            *
  415. .* Input:  &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  416. .*                                                                            *
  417. .* Output: &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  418. .*         &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  419. .*                                                                            *
  420. .* Code: * The following is generated by Procedure                            *
  421. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  422. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  423. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  424. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  425. .*                  - - -                                                     *
  426. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  427. .*       RetAddr    DS.L        1                ; Return address             *
  428. .*       -------------------------------------------------------------------- *
  429. .*       * The following is generated by Var (HERE IN THIS MACRO)             *
  430. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  431. .*       FramePtr   EQU         *                ; A6 will point here         *
  432. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  433. .*                  - - -                                                     *
  434. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  435. .*       -------------------------------------------------------------------- *
  436. .*       * The following is generated by Begin                                *
  437. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  438. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  439. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  440. .*                  ENDR                         ; End of local stack frame   *
  441. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  442. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  443. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  444. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  445. .*       -------------------------------------------------------------------- *
  446. .*       * The following is generated by Enter                                *
  447. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  448. .*       Lbl                                     ; 2ndary entry point label   *
  449. .*                 [WITH        <with>]          ; Cover additional templates *
  450. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  451. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  452. .*       %L%xxxx                                 ; The branch-around label    *
  453. .*       -------------------------------------------------------------------- *
  454. .*       * Body of procedure goes here                                        *
  455. .*       -------------------------------------------------------------------- *
  456. .*       * The following is generated by Return                               *
  457. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  458. .*                 [UNLK        A6]              ; Only if LINK was done      *
  459. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  460. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  461. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  462. .*                 [JMP         (A0)]            ; If not C and have args     *
  463. .*                 [RTS             ]            ; If C or no args            *
  464. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  465. .******************************************************************************
  466. .*
  467.         PRINT    Push,NoMDir,NoMCall
  468. .*
  469.         GBLA        &Link#            ; 1 ==> generate LINK
  470.         GBLA        &HaveDcls#        ; 1 ==> have local variables
  471. .*
  472.         LCLA        &i,&N
  473. .*
  474.     IF NOT &HaveDcls# THEN            ; Is this the first local declaration ?
  475.       &HaveDcls#: SETA 1            ; Yes, indicate we have locals
  476. LinkA6    DS.L      1
  477. FramePtr  EQU       *
  478.     ENDIF
  479. .*
  480. .* Declare each variable on the &SysLst argument list using Dcl1Var#.  Thus the
  481. .* syntax for local variables is identical to proc formals except that here the
  482. .* word alignment is not required.
  483. .*
  484.     &N: SETA &Nbr(&SysLst)
  485.     WHILE &i < &N DO                ; Around and around we go...
  486.       &i: SETA &i+1
  487.       Dcl1Var# &SysLst[&i],0
  488.     ENDW
  489. .*
  490.     &Link#: SETA 1                    ; Now we will require a LINK
  491. .*
  492.         PRINT    Pop
  493.         ENDM
  494.  
  495.         
  496.         TITLE    'Begin - Procedure primary entry point'
  497.         
  498.         MACRO
  499.         Begin    &Prelude,&Save==,&With==
  500. .*
  501. .******************************************************************************
  502. .* Begin - Procedure primary entry point                                      *
  503. .*                                                                            *
  504. .* Input:  &Prelude   = not <null> ==> override generation of LINK            *
  505. .*         &Save      = a register list of regs to save across this procedure *
  506. .*         &With      = a sublist of additional templates to cover with WITH  *
  507. .*                                                                            *
  508. .*         &StFrame#  = name of current stack frame (SF#xxxx)          (SETC) *
  509. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  510. .*         &HaveDcls# = 1 ==> have local variables; 0 ==> no locals    (SETA) *
  511. .*                                                                            *
  512. .* Output: &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  513. .*         &SaveRegs# = Regs saved and to be restored                  (SETC) *
  514. .*         &ArgSize#  = nbr of bytes of stack space for formals        (SETA) *
  515. .*                                                                            *
  516. .* Code: * The following is generated by Procedure                            *
  517. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  518. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  519. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  520. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  521. .*                  - - -                                                     *
  522. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  523. .*       RetAddr    DS.L        1                ; Return address             *
  524. .*       -------------------------------------------------------------------- *
  525. .*       * The following is generated by Var                                  *
  526. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  527. .*       FramePtr   EQU         *                ; A6 will point here         *
  528. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  529. .*                  - - -                                                     *
  530. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  531. .*       -------------------------------------------------------------------- *
  532. .*       * The following is generated by Begin (HERE IN THIS MACRO)           *
  533. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  534. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  535. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  536. .*                  ENDR                         ; End of local stack frame   *
  537. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  538. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  539. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  540. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  541. .*       -------------------------------------------------------------------- *
  542. .*       * The following is generated by Enter                                *
  543. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  544. .*       Lbl                                     ; 2ndary entry point label   *
  545. .*                 [WITH        <with>]          ; Cover additional templates *
  546. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  547. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  548. .*       %L%xxxx                                 ; The branch-around label    *
  549. .*       -------------------------------------------------------------------- *
  550. .*       * Body of procedure goes here                                        *
  551. .*       -------------------------------------------------------------------- *
  552. .*       * The following is generated by Return                               *
  553. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  554. .*                 [UNLK        A6]              ; Only if LINK was done      *
  555. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  556. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  557. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  558. .*                 [JMP         (A0)]            ; If not C and have args     *
  559. .*                 [RTS             ]            ; If C or no args            *
  560. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  561. .******************************************************************************
  562. .*
  563.         PRINT    Push,NoMDir,NoMCall
  564. .*
  565.         GBLC        &FInfo#            ; function <result>
  566.         GBLC        &StFrame#            ; name of current stack frame
  567.         GBLC        &SaveRegs#        ; Regs saved and to be restored
  568.         GBLA        &NbrOfArgs#        ; number of args in argument list
  569.         GBLA        &Link#            ; 1 ==> generate LINK
  570.         GBLA        &HaveDcls#        ; 1 ==> have local variables
  571.         GBLA        &ArgSize#            ; nbr of bytes of stack space for formals
  572. .*
  573. .* If we don't already think we need a LINK, we still may need it if, at this
  574. .* point, we have to save registers and we are in a function or there are formal
  575. .* parameters.
  576. .*
  577.     IF &Link# OR (((&FInfo#≠'') OR (&NbrOfArgs# ≠ 0)) AND (&Save≠'')) THEN
  578.       &Link#: SETA 1                ; Link is required
  579.       IF NOT &HaveDcls# THEN            ; Gen field for LINK address if no locals
  580. LinkA6    DS.L      1
  581.       ENDIF
  582.     ENDIF
  583. .*
  584. .* If there we no locals, we haven't generated the FramePtr yet.  So we do it now.
  585. .*
  586.     IF NOT &HaveDcls# THEN
  587. FramePtr  EQU       *
  588.     ENDIF
  589. .*
  590. .* That's all for the stack frame. We generate LocalSize to be used in potential
  591. .* LINK instruction.
  592. .*
  593. LocalSize DS.W      0
  594.           ENDR
  595. .*
  596. .* Generate a WITH to cover the local stack frame and any additional templates
  597. .* the user specified in the &With parameter.  This may be a sublist or a single
  598. .* name.
  599. .*
  600.     IF &With ≠ '' THEN
  601.       IF &With[1:1] = '(' THEN
  602.           WITH      &With[2:&Len(&With)-2],&StFrame#
  603.       ELSE
  604.           WITH      &With,&StFrame#
  605.       ENDIF
  606.     ELSE
  607.           WITH      &StFrame#
  608.     ENDIF
  609. .*
  610. .* It's time for the LINK.  It is generated if &Link is 1.  &Link became 1 under
  611. .* the following conditions:
  612. .*   1. Either the globals LinkAll or Debug are set non-zero.
  613. .*   2. The &Link Procedure parameter is set to DEBUG or non-null
  614. .*   3. There are local variables (Var's)
  615. .*   4. There are registers to save (&Save), and
  616. .*      • we are processing a function, or
  617. .*      • there are formal (and, of course, actual) parameters
  618. .* Given all this, the user can still suppress the LINK by setting &Prelude to
  619. .* non-null.
  620. .*
  621.     IF &Link# THEN
  622.       IF &Prelude = '' THEN
  623.           LINK      A6,#LocalSize
  624.       ENDIF
  625. FP        SET       A6
  626.     ELSE
  627. FP        SET       A7
  628.     ENDIF
  629. .*
  630. .* Compute the size of the argument list to be able to pop the stack with Return.
  631. .* Also, save registers if required.
  632. .*
  633.     &ArgSize#:  SETA &Eval(&StFrame#)-RetAddr-4
  634.     &SaveRegs#: SETC &Save
  635.     IF &Save ≠ '' THEN
  636.       IF &Substr(&Type(&Save), 1, 3) = 'REG' THEN
  637.           MOVE.L    &Save,-(A7)
  638.       ELSE
  639.           MOVEM.L   &Save,-(A7)
  640.       ENDIF
  641.     ENDIF
  642. .*
  643.         PRINT    Pop
  644.         ENDM
  645.  
  646.         
  647.         TITLE    'Enter - Procedure secondary entry point'
  648.         
  649.         MACRO
  650. &Lbl        Enter    &Prelude,&With==
  651. .*
  652. .******************************************************************************
  653. .* Enter - Procedure secondary entry point                                    *
  654. .*                                                                            *
  655. .* Input:  &Prelude   = not <null> ==> override generation of LINK            *
  656. .*         &With      = a sublist of additional templates to cover with WITH  *
  657. .*                                                                            *
  658. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  659. .*         &SaveRegs# = Regs saved and to be restored                  (SETC) *
  660. .*                                                                            *
  661. .* Output: None.                                                              *
  662. .*                                                                            *
  663. .* Code: * The following is generated by Procedure                            *
  664. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  665. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  666. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  667. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  668. .*                  - - -                                                     *
  669. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  670. .*       RetAddr    DS.L        1                ; Return address             *
  671. .*       -------------------------------------------------------------------- *
  672. .*       * The following is generated by Var                                  *
  673. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  674. .*       FramePtr   EQU         *                ; A6 will point here         *
  675. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  676. .*                  - - -                                                     *
  677. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  678. .*       -------------------------------------------------------------------- *
  679. .*       * The following is generated by Begin                                *
  680. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  681. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  682. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  683. .*                  ENDR                         ; End of local stack frame   *
  684. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  685. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  686. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  687. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  688. .*       -------------------------------------------------------------------- *
  689. .*       * The following is generated by Enter (HERE IN THIS MACRO)           *
  690. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  691. .*       Lbl                                     ; 2ndary entry point label   *
  692. .*                 [WITH        <with>]          ; Cover additional templates *
  693. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  694. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  695. .*       %L%xxxx                                 ; The branch-around label    *
  696. .*       -------------------------------------------------------------------- *
  697. .*       * Body of procedure goes here                                        *
  698. .*       -------------------------------------------------------------------- *
  699. .*       * The following is generated by Return                               *
  700. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  701. .*                 [UNLK        A6]              ; Only if LINK was done      *
  702. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  703. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  704. .*                 [MOVE.<size> <id>,(A7)]       ; If result for function     *
  705. .*                 [JMP         (A0)]            ; If not C and have args     *
  706. .*                 [RTS             ]            ; If C or no args            *
  707. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  708. .******************************************************************************
  709. .*
  710.         PRINT    Push,NoMDir,NoMCall
  711. .*
  712.         GBLC        &SaveRegs#        ; Regs saved and to be restored
  713.         GBLA        &Link#            ; 1 ==> generate LINK
  714. .*
  715. .* Generate a branch around the Enter code
  716. .*
  717.           BRA.S     %L%&SysNdx
  718. &Lbl ;
  719. .*
  720. .* Generate a WITH to cover any additional templates  the user specified in the
  721. .* &With parameter.  This may be a sublist or a single name.
  722. .*
  723.     IF &With ≠ '' THEN
  724.       IF &With[1:1] = '(' THEN
  725.           WITH      &With[2:&Len(&With)-2]
  726.       ELSE
  727.           WITH      &With
  728.       ENDIF
  729.     ENDIF
  730. .*
  731. .* It's time for another LINK.  It is generated if &Link is 1.  &Link became 1
  732. .* under the following conditions:
  733. .*   1. Either the globals LinkAll or Debug are set non-zero.
  734. .*   2. The &Link Procedure parameter is set to DEBUG or non-null
  735. .*   3. There are local variables (Var's)
  736. .*   4. There are registers to save (&Save), and
  737. .*      • we are processing a function, or
  738. .*      • there are formal (and, of course, actual) parameters
  739. .* Given all this, the user can still suppress the LINK by setting &Prelude to
  740. .* non-null.
  741. .*
  742.     IF &Link# THEN
  743.       IF &Prelude = '' THEN
  744.           LINK      A6,#LocalSize
  745.       ENDIF
  746.     ENDIF
  747. .*
  748. .* Save registers if required.
  749. .*
  750.     IF &SaveRegs# ≠ '' THEN
  751.       IF &Substr(&Type(&SaveRegs#), 1, 3) = 'REG' THEN
  752.           MOVE.L    &SaveRegs#,-(A7)
  753.       ELSE
  754.           MOVEM.L   &SaveRegs#,-(A7)
  755.       ENDIF
  756.     ENDIF
  757. .*
  758. .*
  759. .* The Enter branch-around label follows all the Enter code to allow code before
  760. .* the Enter to jump over the Enter.
  761. .*
  762. %L%&SysNdx
  763. .*
  764.         PRINT    Pop
  765.         ENDM
  766.  
  767.  
  768.         TITLE    'Return - Procedure and function exit'
  769.         
  770.         MACRO
  771.         Return    &Result
  772. .*
  773. .******************************************************************************
  774. .* Return - Procedure and function exit                                       *
  775. .*                                                                            *
  776. .* Input:  &Result    = [ <ea> [':' <size> ]                                  *
  777. .*         <size>     = B | W | L | S | D | X | P                             *
  778. .*                                                                            *
  779. .*         &SaveRegs# = Regs saved and to be restored                  (SETC) *
  780. .*         &DbgName#  = name to generate for MacsBug or <null>         (SETC) *
  781. .*         &FSz#      = function result size or <null>                 (SETC) *
  782. .*         &Link#     = 1 ==> generate LINK; 0 ==> no LINK             (SETA) *
  783. .*         &ArgSize#  = nbr of bytes of stack space for formals        (SETA) *
  784. .*         &C#        = 1 ==> C function; 0 ==> Pascal routine         (SETA) *
  785. .*                                                                            *
  786. .* Code: * The following is generated by Procedure                            *
  787. .*       <modname> [PROC         &Scope]         ; PROC may be FUNC | MAIN    *
  788. .*       SF#xxxx    RECORD      {FramePtr},Decr  ; Local stack frame          *
  789. .*      [<modname>  DS.<result> 0]               ; Only if function           *
  790. .*       <formal1>  DS.<size>   <amount>         ; See Dcl1Var# for details   *
  791. .*                  - - -                                                     *
  792. .*       <formalN>  DS.<size>   <amount>         ; Reverse order if C funct   *
  793. .*       RetAddr    DS.L        1                ; Return address             *
  794. .*       -------------------------------------------------------------------- *
  795. .*       * The following is generated by Var                                  *
  796. .*       LinkA6     DS.L        1                ; LINK field before locals   *
  797. .*       FramePtr   EQU         *                ; A6 will point here         *
  798. .*       <Var1>     DS.<size>   <amount>         ; See Dcl1Var# for details   *
  799. .*                  - - -                                                     *
  800. .*       <VarN>     DS.<size>   <amount>         ; One DS for each Var arg    *
  801. .*       -------------------------------------------------------------------- *
  802. .*       * The following is generated by Begin                                *
  803. .*      [LinkA6     DS.L        1]               ; If required and no locals  *
  804. .*      [FramePtr   EQU         *]               ; A6 or A7 will point here   *
  805. .*       LocalSize  DS.W        0                ; Byte size of local vars    *
  806. .*                  ENDR                         ; End of local stack frame   *
  807. .*                  WITH       [<with>,]SF#xxxx  ; Cover templates, stk frame *
  808. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  809. .*       FP         SET         A6 or A7         ; A6 if LINK generated       *
  810. .*                 [MOVE[M].L   <reg-list>,-(A7)]; If regs to save            *
  811. .*       -------------------------------------------------------------------- *
  812. .*       * The following is generated by Enter                                *
  813. .*                  BRA.S       %L%xxxx          ; Branch around Enter code   *
  814. .*       Lbl                                     ; 2ndary entry point label   *
  815. .*                 [WITH        <with>]          ; Cover additional templates *
  816. .*                 [LINK        A6,#LocalSize]   ; If LINK is required        *
  817. .*                 [MOVE[M].L   &Save,-(A7)]     ; If regs to save            *
  818. .*       %L%xxxx                                 ; The branch-around label    *
  819. .*       -------------------------------------------------------------------- *
  820. .*       * Body of procedure goes here                                        *
  821. .*       -------------------------------------------------------------------- *
  822. .*       * The following is generated by Return (HERE IN THIS MACRO)          *
  823. .*                 [MOVE[M].L   (A7)+,<reg-list>]; Restore regs if any saved  *
  824. .*                 [UNLK        A6]              ; Only if LINK was done      *
  825. .*                 [MOVEA.L     (A7)+,A0     ]   ; If not C and have args...  *
  826. .*                 [ADD.W       #<ArgSize>,A7]   ; ...pop off arg list        *
  827. .*                 [MOVE.<size> <ea>,(A7)]       ; If result for function     *
  828. .*                 [JMP         (A0)]            ; If not C and have args     *
  829. .*                 [RTS             ]            ; If C or no args            *
  830. .*                 [DC.B        '<modname>']     ; MacsBug symbol (asis str)  *
  831. .******************************************************************************
  832. .*
  833.         PRINT    Push,NoMDir,NoMCall
  834. .*
  835.         GBLC        &SaveRegs#        ; Regs saved and to be restored
  836.         GBLC        &DbgName#            ; name to generate for MacsBug
  837.         GBLC        &FSz#            ; function result size
  838.         GBLA        &Link#            ; 1 ==> generate LINK
  839.         GBLA        &ArgSize#            ; nbr of bytes of stack space for formals
  840.         GBLA        &C#                ; 1 ==> C function
  841. .*
  842.         LCLC        &S,&Rslt[2]
  843.         LCLA        &i
  844. .*
  845. .* Gen code to restore any save registers
  846. .*
  847.     IF &SaveRegs# ≠ '' THEN
  848.       IF &Substr(&Type(&SaveRegs#), 1, 3) = 'REG' THEN
  849.           MOVE.L    (A7)+,&SaveRegs#
  850.       ELSE
  851.           MOVEM.L   (A7)+,&SaveRegs#
  852.       ENDIF
  853.     ENDIF
  854. .*
  855. .* If we generated the LINK, it's time for the UNLK
  856. .*
  857.     IF &Link# THEN
  858.           UNLK      A6
  859.     ENDIF
  860. .*
  861. .* Generate procedure return to caller: if we are doing a C function, just do an
  862. .* RTS, since it's the caller's responsibility to pop the args off the stack.  If
  863. .* we are generating a Pascal routine, then again we only need an RTS if there
  864. .* were no arguments.  If there were, we pop the arguments off the stack by
  865. .* adding the arg size to A7.  The assembler will optimize the ADD appropriately.
  866. .* Once the arguments are popped we can set the function result using &Result.
  867. .* 
  868. .*
  869.     IF &C# THEN                    ; Just RTS if C function
  870.          RTS
  871.     ELSE                            ; If Pascal...
  872.       IF &ArgSize# > 8 THEN            ; Pop stack if there are args
  873.           MOVEA.L   (A7)+,A0
  874.           LEA       &ArgSize#(A7),A7
  875.       ELSEIF &ArgSize# THEN
  876.           MOVEA.L   (A7)+,A0
  877.           ADD.W     #&ArgSize#,A7
  878.       ELSEIF &Result ≠ '' THEN
  879.           MOVEA.L   (A7)+,A0
  880.       ENDIF
  881.       IF &Result ≠ '' THEN            ; Returning a result to a function ?
  882.         IF &FSz# = '' THEN            ; Yes, we better be in a function!
  883.           AERROR 'Attempt to return a function result in a procedure'
  884.         ELSE                        ; So far, so good
  885.          &i: SETA &List(&Result, '&Rslt', ':')        ; Split &Result
  886.          &S: SETC &Default(&UC(&Trim(&Rslt[2])), &FSz#)    ; Use size override if any
  887.          IF &Pos(&S, 'BWL') THEN        ; B | W | L ==> assume normal MOVE
  888.           MOVE.&S   &Trim(&Rslt[1]),(A7)
  889.          ELSE                    ; S | D | X | P ==> floating point
  890.           FMOVE.&S   &Trim(&Rslt[1]),(A7)
  891.          ENDIF
  892.         ENDIF
  893.       ENDIF
  894.       IF &ArgSize# OR (&Result ≠ '') THEN
  895.           JMP       (A0)
  896.       ELSE
  897.           RTS
  898.       ENDIF
  899.     ENDIF
  900. .*
  901. .* If we need to generate the MacsBug symbol, now is the time!  Be careful to
  902. .* make sure of the Assembler's STRING setting, since the MacsBug symbol must
  903. .* be an ASIS string.
  904. .*
  905.     IF &DbgName# ≠ '' THEN            ; &DbgName# indicates we have a symbol
  906.       &S: SETC &Setting('STRING')        ; Preserve STRING status
  907.       IF &S ≠ 'ASIS' THEN            ; Only change it if not already ASIS
  908.           STRING    ASIS
  909.           DC.B      '&DbgName#'
  910.           STRING    &S
  911.       ELSE
  912.           DC.B      '&DbgName#'
  913.       ENDIF
  914.       DC.W        0                ; Fake literal size
  915.     ENDIF
  916. .*
  917.         PRINT    Pop
  918.         ENDM
  919.  
  920.  
  921.         TITLE    'Call - procedure, function, or trap call'
  922.         
  923.         MACRO
  924.         Call.&Ext    &CallSpec,&Result
  925. .*
  926. .******************************************************************************
  927. .* Call - procedure, function, or trap call                                   *
  928. .*                                                                            *
  929. .* Input:  &Ext      = S | B | W | L | * | <null>                             *
  930. .*         &CallSpec = <modname>[':'<size>] ['('arg1,...argN')']              *
  931. .*         &Result   = PASS | {<id> | CC | POP} [':' <size>] |                *
  932. .*                     (PASS,{<id> | CC} [':' <size>])                        *
  933. .*                                                                            *
  934. .*         <size>    = B | W | L                                              *
  935. .*         <arg-i>   = <null> | NIL | TRUE | FALSE |                          *
  936. .*                     <ea> [':' {<size> | <reg> | A } ]                      *
  937. .*                                                                            *
  938. .* Code: [SUBQ.W    #2|4,A7    ]       ; If function call                     *
  939. .*                                                                            *
  940. .*       [PEA       <arg>      ]       ; If arg:A                             *
  941. .*       [MOVEQ     <arg>,<reg>]       ; If <arg>:<reg>                       *
  942. .*       [MOVE.L    <reg>,-(A7)]       ;  "   "     "                         *
  943. .*       [MOVE.<sz> <arg>,-(A7)]       ; If <arg>:<sz>                        *
  944. .*                                                                            *
  945. .*       [JSR       <modname>  ]       ; If calling code module or import     *
  946. .*       [BSR.<sz>  <modname>  ]       ; If explicit size and not <sz>='*'    *
  947. .*       [<modname>            ]       ; If OPWORD, macro, or "_undefined"    *
  948. .*                                                                            *
  949. .*       [TST.<sz>  (A7)+      ]       ; If result = CC:<sz>                  *
  950. .*       [ADDQ.W    #2|4,A7    ]       ; If result = POP:<sz>                 *
  951. .*       [MOVE.<sz> (A7)+,Rslt ]       ; If result = <rslt>:<sz>              *
  952. .******************************************************************************
  953. .*
  954.         PRINT    Push,NoMDir,NoMCall
  955. .*
  956.         GBLC        &ModName#            ; <modname>
  957.         GBLC        &Args#[50]        ; argument list
  958.         GBLA        &NbrOfArgs#        ; number of args in argument list
  959.         GBLC        &FInfo#            ; Function type if parameterless funct
  960. .*
  961.         LCLA        &i,&Arg
  962.         LCLC        &A[2],&Sz,&Param,&T,&Rslt,&RsltSz
  963. .*
  964. .* Split up the call statement into the globals
  965. .*
  966.     ScanArgs# &CallSpec                ; Set &ModName#, &Args#, &NbrOfArgs#
  967. .*
  968. .* See if we are calling function as indicated by a size on the <modname>. If
  969. .* we are, split off the size from the <modname>, and set &RsltSz with the size
  970. .* to pop off the stack after the call (unless overridden by the &Result param).
  971. .* Reserve space now for the function result.
  972. .*
  973.     IF &NbrOfArgs# = 0 THEN
  974.       &RsltSz: SETC &Default(&UC(&FInfo#), 'W')
  975.       IF &FInfo# ≠ '' THEN
  976.         IF &RsltSz = 'L' THEN
  977.           SUBQ.W    #4,A7
  978.         ELSE
  979.           SUBQ.W    #2,A7
  980.         ENDIF
  981.       ENDIF
  982.     ELSE
  983.       &i:       SETA &List(&ModName#, '&A', ':')
  984.       &ModName#: SETC &Trim(&A[1])
  985.       &RsltSz:   SETC &Default(&UC(&Trim(&A[2])), 'W')
  986.       IF &i = 2 THEN
  987.         IF &RsltSz = 'L' THEN
  988.           SUBQ.W    #4,A7
  989.         ELSE
  990.           SUBQ.W    #2,A7
  991.         ENDIF
  992.       ENDIF
  993.     ENDIF
  994. .*
  995. .* Push each argument on the stack.
  996. .*
  997.     WHILE &Arg < &NbrOfArgs# DO            ; Loop through all of 'em
  998.       &Arg:   SETA &Arg+1
  999.       &A[2]:  SETC ''
  1000.       &i:     SETA &List(&Args#[&Arg], '&A', ':'); Split arg to get its size
  1001.       &Param: SETC &Trim(&A[1])            ; Here's the arg
  1002.       IF &Param ≠ '' THEN                ; I hope, it could be null
  1003.         &Sz: SETC &Default(&UC(&Trim(&A[2])), 'W'); Get arg size
  1004.         IF &Sz = 'A' THEN                ; Should we push address ?
  1005.           PEA       &Param
  1006.         ELSEIF &SubStr(&Type(&Sz), 1, 3) = 'REG' THEN ; Pushing a reg value ?
  1007.           MOVEQ     &Param,&Sz
  1008.           MOVE.L    &Sz,-(A7)
  1009.         ELSE
  1010.              IF &A[2] = '' THEN
  1011.            &T: SETC &UC(&Param)
  1012.             IF &T = 'NIL' THEN            ; Pushing NIL ?
  1013.           CLR.L     -(A7)
  1014.             ELSEIF &T = 'TRUE' THEN        ; Pushing TRUE ?
  1015.           ST        -(A7)
  1016.            ELSEIF &T = 'FALSE' THEN        ; Pushing FALSE ?
  1017.           CLR.B     -(A7)
  1018.             ELSE                        ; Pushing a simple <ea>
  1019.           MOVE.&Sz  &Param,-(A7)
  1020.            ENDIF
  1021.          ELSE                        ; Pushing a simple <ea>
  1022.           MOVE.&Sz  &Param,-(A7)
  1023.          ENDIF
  1024.         ENDIF
  1025.       ENDIF
  1026.     ENDW
  1027. .*
  1028. .* Call the procedure or trap. If the size is "*" or we are calling a import, or
  1029. .* we are calling another module, do a JSR.  If we are calling an OPWORD, macro,
  1030. .* or some undefined name that begins with an underscore, use the name as the
  1031. .* call.  In all other case we BSR to the called routine.
  1032. .*
  1033.     &Sz: SETC &UC(&Ext)
  1034.     IF (&Sz ≠ '*') AND (&Sz ≠ '') THEN
  1035.           BSR.&Sz   &ModName#
  1036.     ELSE
  1037.       &T: SETC &SubStr(&Type(&ModName#), 1, 11)
  1038.       IF &Sz = '*' THEN
  1039.           JSR       &ModName#
  1040.       ELSEIF (&T = 'OPWORD') OR (&T = 'MACRO') OR ((&T='UNDEFINED') AND (&ModName#[1] = '_')) THEN
  1041.           &ModName#
  1042.       ELSEIF (&T='CODE MODULE') OR (&T='CODE IMPORT') OR (&T='UNDEFINED') THEN
  1043.           JSR       &ModName#
  1044.       ELSE
  1045.           BSR       &ModName#
  1046.       ENDIF
  1047.     ENDIF
  1048. .*
  1049. .* If there is an explicit &Result override, we use it to determine what to do
  1050. .* with s function's returned value.  Above, the function invocation possibly
  1051. .* was specified as part of a size attribute on the modname.  That size could
  1052. .* be overridden here with a size attribute on the result.  Whichever way we get
  1053. .* it it is used to pop the function result off the stack (if PASS isn't used).
  1054. .*
  1055.     &Rslt: SETC &Default(&Result, 'PASS'); Default result to PASS
  1056.     IF &UC(&Rslt) ≠ 'PASS' THEN    ; Should we pop the stack ?
  1057.       &i: SETA &Nbr(&Result)        ; Maybe...see how &Result is specified
  1058.       IF (&i>0) AND (&UC(&Result[1]) = 'PASS') THEN; Copy result -- do not pop!
  1059.         &Rslt:   SETC &Result[2]    ; 
  1060.         &A[2]:   SETC ''
  1061.         &i:      SETA &List(&Rslt, '&A', ':') ; Split the result
  1062.         &Rslt:   SETC &UC(&Trim(&A[1]))
  1063.         &RsltSz: SETC &Default(&UC(&Trim(&A[2])), &RsltSz)
  1064.         IF &Rslt = 'CC' THEN        ; Use result as condition code ?
  1065.           TST.&RsltSz (A7)
  1066.         ELSEIF &Rslt = 'POP' THEN    ; Simply pop the stack ?
  1067.           AERROR 'Cannot PASS and POP at the same time!'
  1068.         ELSE                    ; Copy stack into result
  1069.           MOVE.&RsltSz (A7),&A[1]
  1070.         ENDIF
  1071.       ELSE                    ; Pop result off the stack
  1072.         &A[2]:   SETC ''            
  1073.         &i:      SETA &List(&Rslt, '&A', ':') ; Split the result
  1074.         &Rslt:   SETC &UC(&Trim(&A[1]))
  1075.         &RsltSz: SETC &Default(&UC(&Trim(&A[2])), &RsltSz)
  1076.         IF &Rslt = 'CC' THEN        ; Use result as condition code ?
  1077.            TST.&RsltSz (A7)+
  1078.         ELSEIF &Rslt = 'POP' THEN    ; Simply pop the stack ?
  1079.          IF &RsltSz = 'L' THEN
  1080.           ADDQ.W    #4,A7
  1081.          ELSE
  1082.           ADDQ.W    #2,A7
  1083.          ENDIF
  1084.         ELSE                    ; Pop stack into result
  1085.           MOVE.&RsltSz (A7)+,&A[1]
  1086.         ENDIF
  1087.       ENDIF
  1088.     ENDIF
  1089. .*
  1090.         PRINT    Pop
  1091.         ENDM
  1092.  
  1093.         
  1094.         TITLE    'Dump file "ProgStrucMacs.d"'
  1095.         
  1096. ********************************************************************************
  1097.         DUMP        'ProgStrucMacs.d'
  1098. ********************************************************************************
  1099.         END        
  1100.